package Thread;

import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 *Semaphore
 * Semaphore是一种基于计数的信号量。它可以设定一个阈值，基于此，多个线程竞争获取许可信号，
 * 做自己的申请后归还，超过阈值后，线程申请许可信号将会被阻塞。
 * Semaphore可以用来构建一些对象池，资源池之类的，比如数据库连接池，
 * 我们也可以创建计数为1的Semaphore，将其作为一种类似互斥锁的机制，这也叫二元信号量，表示两种互斥状态。它的用法如下：
 * availablePermits函数用来获取当前可用的资源数量
 * wc.acquire(); //申请资源
 * wc.release();// 释放资源
 *
 * By LIBOFEI
 *
 * 需求: 一个厕所只有3个坑位，
 * 但是有10个人来上厕所，那怎么办？假设10的人的编号分别为1-10，并且1号先到厕所，10号最后到厕所。
 * 那么1-3号来的时候必然有可用坑位，顺利如厕，4号来的时候需要看看前面3人是否有人出来了，
 * 如果有人出来，进去，否则等待。同样的道理，4-10号也需要等待正在上厕所的人出来后才能进去，
 * 一切按规则来。
 * **/
class WcRoom extends Thread{
   private Semaphore wc;   //扮演厕所
   private String name;    //扮演上厕所的人的名字

   public WcRoom(Semaphore semaphore,String name){
       this.wc = semaphore;
       this.name = name ;
   }

    @Override
    public void run() {
        try{
            System.out.println( name + "----推开厕所的门.....");
            //获取可用坑位(获取可用的线程数量)
            int wcAble = wc.availablePermits();
            if(wcAble>0){
                System.out.println(name + "+++++还有茅坑.....");
            }else{
                System.out.println(name + "=====开始等待.....");
            }
            //申请坑位(如果线程满了，则等待)
            wc.acquire();
            //只有在有坑位的时候才会入坑(只有线程小于最大线程时才会执行以下代码，否则会等待)
            System.out.println(name +"开始上厕所.....好舒服啊");
            //拉屎时间到(模拟执行业务代码)
            Thread.sleep(new Random().nextInt(2000));
            System.out.println(name + "拉完了......");

        }catch(Exception e){
            e.printStackTrace();
        }finally {
            //出点问题也要释放茅坑(释放许可)
            wc.release();
        }
    }
}

public class ThreadConcurrentSemaphore {

    public static void main(String[] args) {
        //new 信发量对象  最大可执行线程3 (最大茅坑数三个)
        Semaphore semaphore = new Semaphore(3);
        for(int i = 0 ;i < 10; i++){
            new WcRoom(semaphore,"小李" + i).start();
//            wcRoom.start();
        }
    }
}
